package com.example.transaction.service.impl;

import com.example.transaction.mapper.AMapper;
import com.example.transaction.pojo.A;
import com.example.transaction.service.AService;
import com.example.transaction.service.BService;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Time;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Service
public class AServiceImpl implements AService {
    @Autowired
    private AMapper aMapper;


    @Override
    public boolean insert(A a) {
        return aMapper.insertA(a);
    }
    @Override
    public boolean updateByName(String name, Integer money) {
        System.out.println(aMapper.updateAByName(name, money));
        int i=10/0;
        return false;
    }
    @Override
    public A selectByName(String name) {
        return aMapper.selectAByName(name);
    }
    @Override
    public List<A> selectAll() {
        return aMapper.selectAAll();
    }



    //================================传播级别的A事务方法========================================//

    @Autowired
    BServiceImpl bService;
    /**
     * 基本事务的开头方法，基本用REQUIRED
     * 只要是同一个事务或者子事务，无论哪个事务方法出错，都会使得整个事务回滚，即所有操作回滚。
     * 除了PROPAGATION REQUIRES_ NEW
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void REQUIRED(){
        System.out.println(aMapper.updateAByName("a", 10000));
        bService.REQUIRED_ERROR();
//        bService.REQUIRED();
//        int i=10/0;
    }
    /**
     * 当前有事务，则加入当前事务。
     * 当前没有事务，则以非事务执行。即自动提交，每个sql语句都会执行后自动提交，出错不会回滚
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void SUPPORTS(){
        System.out.println(aMapper.updateAByName("a", 10000));
//        bService.SUPPORTS_ERROR();//由于SUPPORTS，当当前有事务时，会加入当前事务，所以SUPPORTS_ERROR报错整个事务会回滚
        //由于当前有事务，所以会加入当前事务中
        bService.SUPPORTS();
        int i=10/0;
    }
    @Transactional(propagation = Propagation.REQUIRED)
    public void REQUIRES_NEW(){
        System.out.println(aMapper.updateAByName("a", 10000));
        bService.REQUIRES_NEW_ERROR();
//        bService.REQUIRES_NEW();
//        int i=10/0;
    }

    /**
     *
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void PROPAGATION_NESTED(){
        System.out.println(aMapper.updateAByName("a", 10000));
        bService.PROPAGATION_NESTED_ERROR();
//        bService.PROPAGATION_NESTED();
//        int i=10/0;
    }


//================================数据库4大事务问题==============================================//
    //======================================脏读==========================//
    /**
     * 脏读的出现:
     *  A的update事务(A事务)更新数据，但未提交，A的select事务(B事务)进行读取，并提交
     *  */
    @Transactional(propagation = Propagation.REQUIRED,timeout = 8)
    public void dirtyRead_Update(){
        System.out.println(aMapper.updateAByName("a", 10000));
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int i=10/0;//DirtyRead事务回滚，即A事务回滚
    }
    @Transactional(propagation = Propagation.REQUIRED,timeout = 8,isolation = Isolation.READ_UNCOMMITTED)//在8秒内一定要完成查询，否则回滚
    public void dirtyRead_Select(){
        System.out.println(aMapper.selectAByName("a"));//这里查出是更新后的结果：即10000,脏读出现
    }

    /**
     * 解决脏读
     *   @Transactional(transactionManager = "transactionManager",propagation = Propagation.REQUIRES_NEW,timeout = 8,isolation = Isolation.READ_COMMITTED)//在8秒内一定要完成查询，否则回滚
     */
    @Transactional(propagation = Propagation.REQUIRED,timeout = 8,isolation = Isolation.READ_COMMITTED)//在8秒内一定要完成查询，否则回滚
    public void solveDirtyRead_Select(){
        System.out.println(aMapper.selectAByName("a"));//这里查出是更新后的结果：即8000
//        System.out.println(aMapper.updateAByName("b",3000));
    }

    //======================================不可重复读==========================//
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
    public void unrepeatableRead_Update(){
        System.out.println(aMapper.updateAByName("a", 10000));
        try {
            TimeUnit.SECONDS.sleep(10);//连同timeout也暂停
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //事务提交
    }
    //注意：保证同一事务，查询的
    //读已经提交或者更低
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
    public void unrepeatableRead_Select(Thread t){
        //在事务A更新后，提交之前，进行查询，结果为8000
        System.out.println(aMapper.selectAByName("a"));
        try {
            t.join();
            //事务A更新后，提交后第二次查询结果为10000,注意：缓存关闭
            System.out.println(aMapper.selectAByName("a"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //设置隔离级别为可重复读
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public void solveUnrepeatableRead_Select(Thread t){
        //在事务A更新后，提交之前，进行查询，结果为8000
        System.out.println(aMapper.selectAByName("a"));
        try {
            t.join();
            //事务A更新后，提交后第二次查询结果为10000,注意：缓存关闭
            System.out.println(aMapper.selectAByName("a"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //======================================幻读==========================//
    //序列化级别以下即可，出现幻读
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public void phantomRead_Insert(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(aMapper.insertA(new A("e", 3000)));
    }
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public void phantomRead_Select(Thread t){
        System.out.println(aMapper.selectAAll());
        try {
            t.join();
            System.out.println(aMapper.selectAAll());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //幻读的解决方法：将隔离级别设置为序列化
    /**
     *  没有意义模拟
     */
}
